# - use libraries
#
# This module provides a USE_LIBRARIES macro, an alternative to the
# FIND_PACKAGE command and the various FindXXX modules. The purpose of
# this macro is to easily search for C and C++ libraries.
#
#  USE_LIBRARIES([<library> ...])
#  USE_LIBRARIES(curses bz2 z pthread) # example
#
# For each library listed, this macro searches for the library and its
# include directories, creating appropriate cache entries, typically
# USE_somelib_LIBRARY and USE_somelib_INCLUDE_DIR, then sets HAVE_somelib
# to TRUE for success or FALSE for failure. This macro lists the results
# for found libraries in the variables LIBRARIES and INCLUDE_DIRS. If
# BUILD_WITH_somelib is defined and false, then the macro ignores somelib
# in its arguments.
#
# Typically, a configuration script would invoke the USE_LIBRARIES
# macro, then check each HAVE_somelib variable. Then it does:
#
#  INCLUDE_DIRECTORIES(${INCLUDE_DIRS})
#  TARGET_LINK_LIBRARIES(sometarget ${LIBRARIES})
#
# This module maintains a database of certain known libraries.
#
# The macro knows explicitly about the following libraries:
#  for compression: bz2 z Xcomp
#  for crypto: crypto gcrypt gnutls gpg-error opencdk ssl uuid
#  for curses: curses edit form menu panel XCurses XPanel
#  for devices: util
#  for fonts: fontconfig freetype fribidi
#  for FOX toolkit: FOX
#  for GTK+ 2: atk cairo glib2 gobject2 gmodule2 gtk2 pango
#  for images: jpeg mng png tiff
#  for math: m
#  for native language support: iconv intl
#  for OpenGL: GL GLU
#  for printing: cups
#  for roguelikes: fov
#  for Qt 4: Qt3Support QtCore QtGui QtNetwork
#            QtOpenGL QtSql QtSvg QtTest QtXml
#  for scripting: lua
#  for SDL: SDL SDL_image SDL_ttf
#  for threading: pthreads
#  for X11: X11 Xaw Xcursor Xext Xfixes Xft Xmu Xpm
#           Xrandr Xrender Xshape XShm Xt
#
# For other libraries, this macro will simply search for a library
# of that name and neglects to search for include directories.

# Object Necromancer: Modules/UseLibraries.cmake --Kernigh, December 2006
# This module is in the public domain and has no copyright.

#               One Module to find them all
#               One Module to seek them
#               One Module to list them all
#               And in the cmake cache link them
#
# The One Module consists of six components:
#  1. a database of known libraries, _USELL_*
#  2. a map of dependencies, _USELD_*
#  3. a symbol map, _USELS_*
#  4. the USE_LIBRARIES macro
#  5. the _USEL_LIBRARY_SPECIAL macro
#  6. the _USEL_HEADER_SPECIAL macro

IF( NOT COMMAND MACRO_LIST_UNIQ )
  INCLUDE( MacroListUniq )
ENDIF( NOT COMMAND MACRO_LIST_UNIQ )
IF( NOT COMMAND PACKAGE_PATHS )
  INCLUDE( UsePackageScript )
ENDIF( NOT COMMAND PACKAGE_PATHS )
FIND_PROGRAM( NM_EXECUTABLE nm )
MARK_AS_ADVANCED( NM_EXECUTABLE )

# Here is the database of known libraries.
# For each library, _USELL_somelib contains four elements:
#  1. package name for PACKAGE_PATHS
#  2. name of the library
#  3. name of a header file
#  4. description of the library
#
# compression
SET( _USELL_bz2        FALSE        bz2         bzlib.h
                       "bzip2 compression" )
SET( _USELL_z          FALSE        z           zlib.h
                       "zlib compression" )
SET( _USELL_Xcomp      FALSE        Xcomp       NX.h
                       "NoMachine's Xcomp library for NX" )
# crypto
SET( _USELL_crypto     FALSE        crypto      openssl/bn.h
                       "OpenSSL cryptography library" )
SET( _USELL_gcrypt     FALSE        gcrypt      gcrypt.h
                       "GNU low-level cryptography library" )
SET( _USELL_gnutls     gnutls       gnutls      gnutls/gnutls.h
                       "GNU TLS 1.0 and SSL 3.0 library" )
SET( _USELL_gpg_error  gpg-error    gpg-error   gpg-error.h
                       "error codes for GNU cryptography" )
SET( _USELL_opencdk    FALSE        opencdk     opencdk.h
                       "OpenCDK for understanding OpenPGP packets" )
SET( _USELL_ssl        FALSE        ssl         ssl/ssl.h
                       "OpenSSL toolkit for SSL 2.0/3.0 ad TLS 1.0" )
SET( _USELL_uuid       uuid         uuid        uuid.h
                       "OSSP uuid, Universally Unique IDentifier" )
# curses
SET( _USELL_curses     FALSE        curses      curses.h
                       "character-cell curses in a tty terminal" )
SET( _USELL_edit       FALSE        edit        histedit.h
                       "line editor for curses" )
SET( _USELL_form       FALSE        form        form.h
                       "forms for curses" )
SET( _USELL_menu       FALSE        menu        menu.h
                       "menus for curses" )
SET( _USELL_panel      FALSE        panel       panel.h
                       "stacked panels for curses" )
SET( _USELL_XCurses    xcurses      XCurses     xcurses/curses.h
                       "character-cell curses in an X11 window" )
SET( _USELL_XPanel     FALSE        XPanel      xcurses/panel.h
                       "stacked panels for XCurses" )
# devices
SET( _USELL_util       FALSE        util        util.h
                       "system utility functions" )
# fonts
SET( _USELL_fontconfig fontconfig   fontconfig  fontconfig/fontconfig.h
                       "font configuration favored by Xft" )
SET( _USELL_freetype   freetype2    freetype    SPECIAL
                       "freetype2 font engine" )
SET( _USELL_fribidi    fribidi      fribidi     fribidi/fribidi.h
                       "fribidi for layout of bidirectional fonts" )
# FOX
SET( _USELL_FOX        fox          FOX-1.6     fx.h
                       "FOX widget set, Free Objects for X" )
# GTK+ 2
SET( _USELL_atk        atk          atk-1.0     atk/atk.h
                       "Accessibility ToolKit, wanted by GTK+ 2" )
SET( _USELL_cairo      cairo        cairo       cairo.h
                       "Cairo vector graphics, wanted by GTK+ 2" )
SET( _USELL_glib2      glib-2.0     glib-2.0    glib.h,glibconfig.h
                       "lists, hashes and miscellaneous, wanted by GTK+ 2" )
SET( _USELL_gobject2   gobject-2.0  gobject-2.0 glib-object.h
                       "GLib object library, wanted by GTK+ 2" )
SET( _USELL_gmodule2   gmodule-2.0  gmodule-2.0 gmodule.h
                       "GLib module loader, wanted by GTK+ 2" )
SET( _USELL_gtk2       gtk+-x11-2.0 gtk-x11-2.0 gtk/gtk.h,gdkconfig.h
                       "GTK+ 2 widget set" )
SET( _USELL_pango      pango        pango-1.0   pango/pango.h
                       "Pango text layout, wanted by GTK+ 2" )
# images
SET( _USELL_jpeg       FALSE        jpeg        jpeglib.h
                       "JPEG/JFIF images" )
SET( _USELL_mng        FALSE        mng         libmng.h
                       "Multiple-image Network Graphics (MNG)" )
SET( _USELL_png        libpng       png         png.h
                       "Portable Network Graphics (PNG)" )
SET( _USELL_tiff       FALSE        tiff        tiff.h
                       "TIFF images" )
# math
SET( _USELL_m          FALSE        m           math.h
                       "C math functions" )
# native language support
SET( _USELL_iconv      FALSE        iconv       iconv.h
                       "iconv for converting between character sets" )
SET( _USELL_intl       FALSE        intl        libintl.h
                       "gettext library" )
# OpenGL
SET( _USELL_GL         FALSE        GL          GL/gl.h
                       "GL for 3D graphics" )
SET( _USELL_GLU        FALSE        GLU         GL/glu.h
                       "GLU for 3D graphics" )
# printing
SET( _USELL_cups       cups         cups        cups/cups.h
                       "printing with Common Unix Printing System (CUPS)" )
# Qt 4
FOREACH( lib Qt3Support QtCore QtGui QtNetwork
             QtOpenGL QtSql QtSvg QtTest QtXml )
  SET( _USELL_${lib}   ${lib}       ${lib}      ${lib}/${lib},${lib}
                       "${lib} of Qt 4" )
ENDFOREACH( lib )
# roguelikes
SET( _USELL_fov        FALSE        fov         fov/fov.h
                       "field of view library" )
# scripting
SET( _USELL_lua        FALSE        lua         lua.h
                       "Lua programming language for extending applications" )
# SDL
SET( _USELL_SDL        sdl          SDL         SDL.h
                       "SDL for cross-platform graphics and audio" )
SET( _USELL_SDL_image  FALSE        SDL_image   SDL_image.h
                       "SDL_image for drawing images with SDL" )
SET( _USELL_SDL_mixer  FALSE        SDL_mixer   SDL_mixer.h
                       "SDL_mixer for mixing various audio formats with SDL" )
SET( _USELL_SDL_net    FALSE        SDL_net     SDL_net.h
                       "SDL_net for cross-platform networking" )
SET( _USELL_SDL_ttf    FALSE        SDL_ttf     SDL_ttf.h
                       "SDL_ttf for TrueType fonts with SDL" )
# threading
SET( _USELL_pthread    FALSE        SPECIAL     pthread.h
                       "POSIX threads" )
# X11
SET( _USELL_X11        FALSE        X11         X11/X.h
                       "Xlib for X11 clients" )
SET( _USELL_Xaw        FALSE        Xaw         SPECIAL
                       "Xaw, the X11 Athena Widgets" )
SET( _USELL_Xcursor    xcursor      Xcursor     X11/Xcursor/Xcursor.h
                       "Xcursor for better X11 cursors" )
SET( _USELL_Xext       FALSE        Xext        X11/extensions/Xext.h
                       "extensions to X11" )
SET( _USELL_Xfixes     FALSE        Xfixes      X11/extensions/Xfixes.h
                       "Xfixes to X11" )
SET( _USELL_Xft        xft          Xft         X11/Xft/Xft.h
                       "X Freetype for better X11 fonts" )
SET( _USELL_Xmu        FALSE        Xmu         X11/Xmu/Xmu.h
                       "utilities to support Xaw" )
SET( _USELL_Xpm        FALSE        Xpm         SPECIAL
                       "X pixmaps" )
SET( _USELL_Xrandr     FALSE        Xrandr      X11/extensions/Xrandr.h
                       "X Resize, Rotate and Reflection" )
SET( _USELL_Xshape     FALSE        FALSE       X11/extensions/shape.h
                       "X11 Nonrectangular Window Shape" )
SET( _USELL_XShm       FALSE        FALSE       X11/extensions/XShm.h
                       "X Shared Memory" )
SET( _USELL_Xt         FALSE        Xt          X11/Intrinsic.h
                       "X toolkit intrinsics" )

# Here is the map of dependencies. This maps each library to the
# list of other libraries for which we need header files.
#   * For example, Xft header files require the freetype header files,
#     thus SET( _USELD_Xft freetype ).
#   * CUPS header files require not any GnuTLS nor OpenSSL header files,
#     so we have no _USELD_cups entry.
#
# curses
SET( _USELD_form       curses )
SET( _USELD_menu       curses )
SET( _USELD_panel      curses )
SET( _USELD_XPanel     XCurses )
# crypto
SET( _USELD_gcrypt     gpg_error )
# GTK+ 2
SET( _USELD_atk        gobject2 gmodule2 )
SET( _USELD_gobject2   glib2 )
SET( _USELD_gmodule2   glib2 )
SET( _USELD_gtk2       atk cairo pango )
SET( _USELD_pango      gobject2 gmodule2 )
# Qt4
SET( _USELD_Qt3Support QtCore )
SET( _USELD_QtGui      QtCore )
SET( _USELD_QtNetwork  QtCore )
SET( _USELD_QtOpenGL   QtCore GL GLU )
SET( _USELD_QtSql      QtCore )
SET( _USELD_QtSvg      QtCore )
SET( _USELD_QtTest     QtCore )
SET( _USELD_QtXml      QtCore )
# X11
SET( _USELD_Xaw        X11 Xmu )
SET( _USELD_Xft        freetype )
SET( _USELD_Xpm        X11 Xext )

# Here is the symbol map. If some library wants the symbol XXX,
# then we add the _USELS_XXX library.
#
# compression
SET( _USELS_BZ2_bzCompress         bz2 )
SET( _USELS_BZ2_bzDecompress       bz2 )
SET( _USELS_deflate                z )
SET( _USELS_inflate                z )
# crypto
SET( _USELS_gcry_control           gcrypt )
SET( _USELS_gnutls_init            gnutls )
# images
SET( _USELS_jpeg_read_header       jpeg )
SET( _USELS_png_create_info_struct png )
SET( _USELS_TIFFClientOpen         tiff )
# math
SET( _USELS_sqrt                   m )
# natural language support
SET( _USELS_gettext                intl )
SET( _USELS_libiconv               iconv )
# printing
SET( _USELS_cupsGetDests           cups )
# threading
SET( _USELS_pthread_create         pthread )
# X11
SET( _USELS_XawScrollbarSetThumb   Xaw )     # from XCurses
SET( _USELS_XOpenDisplay           X11 )
SET( _USELS_XFixesSetCursorName    Xfixes )  # from Xcursor
SET( _USELS_XftFontOpen            Xft )
SET( _USELS_XftFontOpenName        Xft )
SET( _USELS_XftFontOpenPattern     Xft )
SET( _USELS_XftFontOpenXlfd        Xft )
SET( _USELS_XRRQueryExtension      Xrandr )
SET( _USELS_XtWindow               Xt )

# HACK: for each _USELS_* variable, put the symbol name in _USELS_
# as a regex for egrep, as "(deflate|inflate|sqrt)"
GET_CMAKE_PROPERTY( _usel_value VARIABLES )
SET( _USELS "(" )
FOREACH( var ${_usel_value} )
  # prepend xxx to force string match, not variable match
  IF( "xxx${var}" MATCHES "^xxx_USELS_" )
    STRING( REGEX REPLACE "^_USELS_(.*)$" \\1 _usel_value "${var}" )
    SET( _USELS "${_USELS}|${_usel_value}" )
  ENDIF( "xxx${var}" MATCHES "^xxx_USELS_" )
ENDFOREACH( var )
STRING( REGEX REPLACE "^\\(\\|" "(" _USELS "${_USELS}" ) # (| to (
SET( _USELS "${_USELS})" )
SET( _usel_value )

# Here is the USE_LIBRARIES macro.
#  1. clear LIBRARIES and INCLUDE_DIRS
#  2. copy ARGV to _usel_argv, honoring BUILD_WITH_*
#  3. add dependencies to _usel_argv
#  4. create search paths _usel_isp, _usel_lsp
#  5. find each library
#  6. follow symbol map
#
MACRO( USE_LIBRARIES )
  SET( LIBRARIES )
  SET( INCLUDE_DIRS )

  # [2.] Copy arguments from ARGV to _usel_argv.
  # Ignore argument ${lib} if BUILD_WITH_${lib} is defined and false.
  SET( _usel_argv )
  FOREACH( lib ${ARGV} )
    # cmake gives precedence to NOT before evaluating OR
    IF( NOT DEFINED BUILD_WITH_${lib} OR BUILD_WITH_${lib} )
      LIST( APPEND _usel_argv ${lib} )
    ENDIF( NOT DEFINED BUILD_WITH_${lib} OR BUILD_WITH_${lib} )
  ENDFOREACH( lib )

  # [3.] Use map to add dependencies to _usel_argv.
  SET( _usel_loop TRUE )
  WHILE( _usel_loop )
    SET( _usel_loop FALSE )
    FOREACH( lib ${_usel_argv} ) # For each library...
      IF( _USELD_${lib} )        # ...if library has dependencies...
        # ...copy the list of dependencies to _usel_deps.
        STRING( CONFIGURE "@_USELD_${lib}@" _usel_deps )
        FOREACH( dep ${_usel_deps} )
          IF( NOT ";${_usel_argv};" MATCHES ";${dep};" )
            LIST( APPEND _usel_argv ${dep} ) # Add the dependency.
            IF( _USELD_${dep} )
              SET( _usel_loop TRUE ) # Dependency has dependencies.
            ENDIF( _USELD_${dep} )
          ENDIF( NOT ";${_usel_argv};" MATCHES ";${dep};" )

          IF( DEFINED BUILD_WITH_${dep} AND NOT BUILD_WITH_${dep} )
            MESSAGE( STATUS "Warning: ${lib} requires ${dep}; "
                          "overriding BUILD_WITH_${dep} option." )
          ENDIF( DEFINED BUILD_WITH_${dep} AND NOT BUILD_WITH_${dep} )
        ENDFOREACH( dep )
      ENDIF( _USELD_${lib} )
    ENDFOREACH( lib )
  ENDWHILE( _usel_loop )

  # [4.] Use PACKAGE_PATHS to create lists of nonstandard
  # include search path (ISP) and library search path (LSP).
  SET( _usel_isp )
  SET( _usel_lsp )
  FOREACH( lib ${_usel_argv} )
    # If library is in our database...
    IF( _USELL_${lib} )
      # Get package name from database.
      LIST( GET _USELL_${lib} 0 _usel_package )
      # If there is a package name...
      IF( _usel_package )
        # Obtain the paths for this package.
        PACKAGE_PATHS( ${_usel_package} _usel_package_isp _usel_package_lsp )
        # Add the paths to our lists.
        SET( _usel_isp ${_usel_isp} ${_usel_package_isp} )
        SET( _usel_lsp ${_usel_lsp} ${_usel_package_lsp} )
      ENDIF( _usel_package )
    ENDIF( _USELL_${lib} )
  ENDFOREACH( lib )

  # [5.] Search for each library.
  FOREACH( lib ${_usel_argv} )
    # If there is a database entry...
    IF( _USELL_${lib} )
      _USEL_QUERY( ${lib} )   # Query database.
      _USEL_LIBRARY( ${lib} ) # Add library to LIBRARIES.
      IF( _usel_found )       # If library not missing...
        _USEL_HEADER( ${lib} )  # ...add headers to INCLUDE_DIRS.
      ENDIF( _usel_found )

      # Now we can copy _usel_found to HAVE_${lib}.
      SET( HAVE_${lib} ${_usel_found} )

    ELSE( _USELL_${lib} )
      MESSAGE( STATUS "Warning: no UseLibraries database entry for ${lib}" )

      # The default behavior is simply to find the library of that name.
      SET( HAVE_${lib} FALSE )
      FIND_LIBRARY( USE_${lib}_LIBRARY ${lib} ${_usel_lsp} )
      IF( USE_${lib}_LIBRARY )
        STRING( CONFIGURE "@USE_${lib}_LIBRARY@" _usel_value )
        LIST( APPEND LIBRARIES ${_usel_value} )
        SET( HAVE_${lib} TRUE )
      ENDIF( USE_${lib}_LIBRARY )

    ENDIF( _USELL_${lib} )
  ENDFOREACH( lib )
  MACRO_LIST_UNIQ( INCLUDE_DIRS ${INCLUDE_DIRS} )

  # [6.] Follow symbol map.
  SET( _usel_loop TRUE )
  SET( _usel_libs )
  SET( _usel_hex "[0-9a-fA-F][0-9a-fA-F]+" ) # regex for symbol values
  SET( _usel_und "[ \t][ \t]+" )             # regex for missing value
  SET( _usel_typ "[ \t]+.[ \t]+" )           # regex for symbol type
  WHILE( _usel_loop )
    SET( _usel_want  "" ) # list of wanted symbols
    SET( _usel_found "" ) # list of found symbols
    GET_CMAKE_PROPERTY( dump VARIABLES )

    # search for wanted symbols
    FOREACH( file ${LIBRARIES} )
      IF( EXISTS ${file} ) # if file is a file, not a -pthread flag
        # nm -g (global) -p (print without sort)
        MESSAGE( STATUS "Examining symbols of ${file}" )
        EXECUTE_PROCESS(
          COMMAND ${NM_EXECUTABLE} -gp ${file}
          COMMAND egrep "${_USELS}" # increase speed
          COMMAND tr \n \;          # increase speed versus STRING
          OUTPUT_VARIABLE _usel_nm )
        #STRING( REGEX REPLACE \n \; _usel_nm "${_usel_nm}" )
        FOREACH( line ${_usel_nm} )

          # if the symbol has a value
          IF( ${line} MATCHES "^${_usel_hex}${_usel_typ}" )
            STRING( REGEX REPLACE "^${_usel_hex}${_usel_typ}_*(.*)$" \\1
                    _usel_symbol ${line} )         # extract symbol
            IF( _USELS_${_usel_symbol} )
              # add this symbol to found
              LIST( APPEND _usel_found ${_usel_symbol} )
            ENDIF( _USELS_${_usel_symbol} )
          ENDIF( ${line} MATCHES "^${_usel_hex}${_usel_typ}" )

          # if the symbol is undefined
          IF( ${line} MATCHES "^${_usel_und}${_usel_typ}" )
            STRING( REGEX REPLACE "^${_usel_und}${_usel_typ}_*(.*)$" \\1
                    _usel_symbol ${line} )         # extract symbol
            IF( _USELS_${_usel_symbol} )
              # add this symbol to want
              LIST( APPEND _usel_want ${_usel_symbol} )
            ENDIF( _USELS_${_usel_symbol} )
          ENDIF( ${line} MATCHES "^${_usel_und}${_usel_typ}" )
        ENDFOREACH( line )
      ENDIF( EXISTS ${file} )
    ENDFOREACH( file )

    # remove found symbols from want
    IF( _usel_found )
      LIST( REMOVE_ITEM _usel_want ${_usel_found} )
    ENDIF( _usel_found )

    # clear LIBRARIES so that we can create the next list
    SET( _usel_libs ${_usel_libs} ${LIBRARIES} )
    SET( LIBRARIES )

    IF( _usel_want )
      # use symbols to create next list of LIBRARIES
      FOREACH( symbol ${_usel_want} )
        STRING( CONFIGURE "@_USELS_${symbol}@" _usel_value )
        _USEL_QUERY( ${_usel_value} )
        _USEL_LIBRARY( ${_usel_value} )
      ENDFOREACH( symbol ${_usel_want} )
      MACRO_LIST_UNIQ( LIBRARIES ${LIBRARIES} ) # remove duplicates
      LIST( REMOVE_ITEM LIBRARIES _usel_libs )  # remove more duplicates
    ELSE( _usel_want )
      SET( LIBRARIES ${_usel_libs} )
      SET( _usel_loop FALSE ) # break WHILE
    ENDIF( _usel_want )
  ENDWHILE( _usel_loop )
ENDMACRO( USE_LIBRARIES )

# The _USEL_QUERY macro sets some global variables for
# USE_LIBRARIES by looking in the _USELL_* database.
#  _usel_library     (name of the library)
#  _usel_header      (name of a header file)
#  _usel_description (description of the library)
#  _usel_found       (TRUE)
MACRO( _USEL_QUERY lib )
  LIST( GET _USELL_${lib} 1 _usel_library )
  LIST( GET _USELL_${lib} 2 _usel_header )
  LIST( GET _USELL_${lib} 3 _usel_description )
  STRING( REGEX REPLACE , \; _usel_header "${_usel_header}" )
  SET( _usel_found TRUE )
ENDMACRO( _USEL_QUERY lib )

# The _USEL_LIBRARY macro finds finds a library and appends the library
# to LIBRARIES. It uses these parameters and global variables:
#  lib               (name of database entry)
#  _usel_lsp         (library search path)
#  _usel_library     (from _USEL_QUERY)
#  _usel_description (from _USEL_QUERY)
#  _usel_found       (set FALSE if not found)
MACRO( _USEL_LIBRARY lib )
  IF( _usel_library ) # If there is a library...
    SET( _usel_found FALSE )
    IF( _usel_library STREQUAL SPECIAL )
      _USEL_LIBRARY_SPECIAL( ${lib} )

    ELSE( _usel_library STREQUAL SPECIAL )
      # Find library and store path in advanced cache variable.
      FIND_LIBRARY( USE_${lib}_LIBRARY ${_usel_library} ${_usel_lsp}
                    DOC "Path to library of ${_usel_description}." )
      MARK_AS_ADVANCED( USE_${lib}_LIBRARY )

      # If we found the library, then append it to LIBRARIES.
      IF( USE_${lib}_LIBRARY )
        SET( _usel_found TRUE )
        STRING( CONFIGURE "@USE_${lib}_LIBRARY@" _usel_value )
        LIST( APPEND LIBRARIES ${_usel_value} )
      ENDIF( USE_${lib}_LIBRARY )

    ENDIF( _usel_library STREQUAL SPECIAL )
  ENDIF( _usel_library )
ENDMACRO( _USEL_LIBRARY )

# The _USEL_HEADER macro finds finds the header files and appends
# their directories to INCLUDE_DIRS.
#  lib               (name of database entry)
#  _usel_isp         (header search path)
#  _usel_header      (from _USEL_QUERY)
#  _usel_description (from _USEL_QUERY)
#  _usel_found       (set FALSE if not found)
MACRO( _USEL_HEADER )
  IF( _usel_header ) # If there are headers...
    SET( _usel_count 0 )
    FOREACH( header ${_usel_header} )
      SET( _usel_found FALSE )
      MATH( EXPR _usel_count "${_usel_count} + 1" )

      IF( ${header} STREQUAL SPECIAL )
        _USEL_HEADER_SPECIAL( ${lib} )

      ELSE( ${header} STREQUAL SPECIAL )
      # Find include directory and store path in advanced cache variable.
      FIND_PATH( USE_${lib}_INCLUDE_DIR_${_usel_count} ${header} ${_usel_isp}
                 DOC "Path to header files of ${_usel_description}." )
      MARK_AS_ADVANCED( USE_${lib}_INCLUDE_DIR_${_usel_count} )

      # If we found the include directory, then append it to INCLUDE_DIRS.
      IF( USE_${lib}_INCLUDE_DIR_${_usel_count} )
        SET( _usel_found TRUE )
        STRING( CONFIGURE "@USE_${lib}_INCLUDE_DIR_${_usel_count}@"
                _usel_value )
        LIST( APPEND INCLUDE_DIRS ${_usel_value} )
      ENDIF( USE_${lib}_INCLUDE_DIR_${_usel_count} )

      ENDIF( ${header} STREQUAL SPECIAL )
    ENDFOREACH( header )
  ENDIF( _usel_header )
ENDMACRO( _USEL_HEADER )

# Some libraries give SPECIAL for their library or header file.
# SPECIAL handlers can use these global variables from USE_LIBRARIES:
#  _usel_isp _usel_lsp
#  _usel_library _usel_header _usel_description
#  _usel_found
#
# ${lib} is a constant parameter substitution, not a variable!

# Handler for libraries named SPECIAL...
MACRO( _USEL_LIBRARY_SPECIAL lib )
  SET( _usel_handled FALSE )

  IF( ${lib} STREQUAL pthread )
    # Special situation: pass a specific flag to the compiler.
    IF( CMAKE_SYSTEM_NAME STREQUAL OpenBSD )
      # use -pthread following directions in pthreads(3)
      SET( USE_pthread_LIBRARY "-pthread" CACHE STRING
           "Flag for linking programs that use POSIX threads." )
    ELSE( CMAKE_SYSTEM_NAME STREQUAL OpenBSD )
      # Darwin, FreeBSD, GNU/Linux, NetBSD, ...
      SET( USE_pthread_LIBRARY "-lpthread" CACHE STRING
           "Flag to link programs that use POSIX threads." )
    ENDIF( CMAKE_SYSTEM_NAME STREQUAL OpenBSD )
    MARK_AS_ADVANCED( USE_pthread_LIBRARY )

    IF( USE_pthread_LIBRARY )
      LIST( APPEND LIBRARIES ${USE_pthread_LIBRARY} )
    ENDIF( USE_pthread_LIBRARY )

    SET( _usel_found TRUE ) # FIXME we should check if the flag works

    SET( _usel_handled TRUE )
  ENDIF( ${lib} STREQUAL pthread )

  IF( NOT _usel_handled )
    MESSAGE( FATAL_ERROR "Error in UseLibraries database: "
             "missing SPECIAL library handler for ${lib}" )
  ENDIF( NOT _usel_handled )
ENDMACRO( _USEL_LIBRARY_SPECIAL )

# Hander for header files named SPECIAL...
MACRO( _USEL_HEADER_SPECIAL lib )
  SET( _usel_handled FALSE )

  IF( ${lib} STREQUAL freetype )
    # Special situation: please find both ft2build.h and either
    # freetype/ftconfig.h or freetype2/ftconfig.h.
    FIND_PATH( USE_freetype_INCLUDE_DIR_1 ft2build.h ${_usel_isp}
               DOC "Path to ft2build.h of freetype2." )
    FIND_PATH( USE_freetype_INCLUDE_DIR_2
      NAMES freetype/config/ftconfig.h freetype2/config/ftconfig.h
      PATHS ${_usel_isp}
      DOC "Path to other header files of freetype2." )
    MARK_AS_ADVANCED( USE_freetype_INCLUDE_DIR_1 USE_freetype_INCLUDE_DIR_2 )

    IF( USE_freetype_INCLUDE_DIR_1 AND USE_freetype_INCLUDE_DIR_2 )
      LIST( APPEND INCLUDE_DIRS ${USE_freetype_INCLUDE_DIR_1}
                                ${USE_freetype_INCLUDE_DIR_2} )
      SET( _usel_found TRUE )
    ENDIF( USE_freetype_INCLUDE_DIR_1 AND USE_freetype_INCLUDE_DIR_2 )

    SET( _usel_handled TRUE )
  ENDIF( ${lib} STREQUAL freetype )

  IF( ${lib} STREQUAL Xaw )
    # Special situation: please find X11/Xaw/XawInit.h but allow
    # compiler to see also Xaw/XawInit.h.
    FIND_PATH( USE_Xaw_INCLUDE_DIR_1 X11/Xaw/XawInit.h ${_usel_isp}
               DOC "Path to X11/Xaw/XawInit.h of Xaw." )
    SET( USE_Xaw_INCLUDE_DIR_2 ${USE_Xaw_INCLUDE_DIR_1}/X11
         CACHE PATH "Path to Xaw/XawInit.h of Xaw." FORCE )

    IF( USE_Xaw_INCLUDE_DIR_1 AND USE_Xaw_INCLUDE_DIR_2 )
      LIST( APPEND INCLUDE_DIRS ${USE_Xaw_INCLUDE_DIR_1}
                                ${USE_Xaw_INCLUDE_DIR_2} )
      SET( _usel_found TRUE )
    ENDIF( USE_Xaw_INCLUDE_DIR_1 AND USE_Xaw_INCLUDE_DIR_2 )

    SET( _usel_handled TRUE )
  ENDIF( ${lib} STREQUAL Xaw )

  IF( ${lib} STREQUAL Xpm )
    # Special situation: find X11/xpm.h and also xpm.h.
    FIND_PATH( USE_Xaw_INCLUDE_DIR_1 X11/xpm.h ${_usel_isp}
               DOC "Path to X11/xpm.h of Xpm." )
    SET( USE_Xaw_INCLUDE_DIR_2 ${USE_Xaw_INCLUDE_DIR_1}/X11
         CACHE PATH "Path to xpm.h of Xpm." FORCE )

    IF( USE_Xpm_INCLUDE_DIR_1 AND USE_Xpm_INCLUDE_DIR_2 )
      LIST( APPEND INCLUDE_DIRS ${USE_Xpm_INCLUDE_DIR_1}
                                ${USE_Xpm_INCLUDE_DIR_2} )
      SET( _usel_found TRUE )
    ENDIF( USE_Xpm_INCLUDE_DIR_1 AND USE_Xpm_INCLUDE_DIR_2 )

    SET( _usel_handled TRUE )
  ENDIF( ${lib} STREQUAL Xpm )

  IF( NOT _usel_handled )
    MESSAGE( FATAL_ERROR "Error in UseLibraries database: "
             "missing SPECIAL header file handler for ${lib}" )
  ENDIF( NOT _usel_handled )
ENDMACRO( _USEL_HEADER_SPECIAL )
